package edu.yngsxy.dsstudyApi.core.ai.service;

import cn.hutool.ai.core.AIService;
import cn.hutool.ai.core.Message;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.yngsxy.dsstudyApi.core.ai.service.AiMessageDto;
import edu.yngsxy.dsstudyApi.core.ai.service.ModelResponseParser;
import edu.yngsxy.dsstudyApi.core.ai.service.MultiTurnChatMessage;
import edu.yngsxy.dsstudyApi.core.exception.BusinessException;
import edu.yngsxy.dsstudyApi.core.util.WkRedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 多轮对话服务 - 高性能简洁版，支持100条历史消息
 */
//@Service
@Slf4j
public abstract class WkAIService {
    private static final String REDIS_KEY_PREFIX = "wk_ai_chat:";
    private static final int MAX_HISTORY = 100; // 100条历史消息
    private static final int EXPIRE_HOURS = 24;// 24小时过期

    private final StringRedisTemplate redis;// Redis客户端
    private final ObjectMapper mapper;// JSON序列化工具
    private ModelResponseParser modelResponseParser;// 模型响应解析器
    private WkRedisService wkRedisService;// Redis服务

    public WkAIService(StringRedisTemplate redis, ObjectMapper mapper,WkRedisService wkRedisService) {// 构造函数注入依赖
        this.redis = redis;
        this.mapper = mapper;
        this.modelResponseParser = new ModelResponseParser(mapper);// 初始化模型响应解析器
        this.wkRedisService=wkRedisService;
    }

    /**
     * 获取AI服务实例 - 子类重写
     * @return AI服务实例
     */
    protected abstract AIService getAiService();
    /**
     * 单轮对话
     * @param msg 用户输入
     * @return AI回复
     */
    public String chat(String msg,String modelName) {
        AIService aiService= checkAIService();// 获取AI服务实例
        String response = aiService.chat(msg);// 调用Hutool AI服务
        return this.modelResponseParser.parse(response, modelName);// 解析AI回复
    }

    /**
     * 检查AI服务是否初始化
     * @return AI服务实例
     */
    private  AIService  checkAIService() {
        AIService aiService= getAiService();
        if (aiService== null) {// 未初始化
            log.error("AI服务未初始化");
            throw new IllegalArgumentException("AI服务未初始化");
        }
        return aiService;
    }
    /**
     * 处理多轮对话请求 - 简洁高性能版
     */
    public Map<String, Object> chat(MultiTurnChatMessage msg, String modelName) {
        AIService aiService= checkAIService();
        if (msg == null || !StringUtils.hasText(msg.getUserId()) || !StringUtils.hasText(msg.getMsg())) {
            throw new IllegalArgumentException("多轮对话请求参数错误，缺失userId或msg");
        }

        String sessionId = StringUtils.hasText(msg.getSessionId()) ? msg.getSessionId() : genSessionId(msg.getUserId());

        try {
            // 获取历史消息
            List<Message> messages = getHistory(sessionId);

            // 添加用户消息
            messages.add(new Message("user", msg.getMsg()));

            // 调用AI服务
            String rawAnswer = aiService.chat(messages);
            // 解析AI回答，提取真正的答案内容
            String answer =this.modelResponseParser.parse(rawAnswer, modelName);
            // 添加AI回复并保存历史
            messages.add(new Message( "assistant", answer));

            // 异步保存历史
            saveHistoryAsync(sessionId, messages);

            // 返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("sessionId", sessionId);
            result.put("answer", answer);
            result.put("historySize", messages.size());
            return result;

        } catch (Exception e) {
            log.error("多轮对话请求处理失败,userId: {}, sessionId: {},error: {}", msg.getUserId(), sessionId, e);
            throw new BusinessException("多轮对话请求处理失败:" + e.getMessage());
        }
    }

    /**
     * 从Redis获取历史消息
     */
    public List<Message> getHistory(String sessionId) {
        try {
            String json = redis.opsForValue().get(sessionId);
            if (StringUtils.hasText(json)) {
                // 反序列化为自定义DTO列表
                List<AiMessageDto> dtos = mapper.readValue(
                        json,
                        new TypeReference<List<AiMessageDto>>() {
                        }
                );

                // 转换为Hutool的Message对象
                return dtos.stream()
                        .map(AiMessageDto::toHutoolMessage)
                        .collect(Collectors.toList());
            }
        } catch (JsonProcessingException e) {
            log.error("解析历史消息失败: {}", sessionId, e);
        } catch (Exception e) {
            log.error("获取历史消息失败: {}", sessionId, e);
        }

        return new ArrayList<>();
    }

    /**
     * 异步保存历史消息到Redis
     */
    @Async // 异步执行  在多线程环境下，可以提高性能，需要配在主类上注解@EnableAsync
    public void saveHistoryAsync(String sessionId, List<Message> messages) {
        try {
            // 限制历史长度
            if (messages.size() > MAX_HISTORY) {
                messages = new ArrayList<>(messages.subList(messages.size() - MAX_HISTORY, messages.size()));
            }

            // 转换为自定义DTO列表
            List<AiMessageDto> dtos = messages.stream()
                    .map(AiMessageDto::fromHutoolMessage)
                    .collect(Collectors.toList());

            // 保存到Redis
            String json = mapper.writeValueAsString(dtos);
            redis.opsForValue().set(sessionId, json, EXPIRE_HOURS, TimeUnit.HOURS);
        } catch (Exception e) {
            log.error("保存历史消息失败: {}", sessionId, e);
        }
    }

    /**
     * 生成会话ID
     */
    protected String genSessionId(String userId) {
        return REDIS_KEY_PREFIX + userId + ":" + UUID.randomUUID();
    }

    /**
     * 清除指定会话的历史记录
     */
    public boolean clearHistory(String sessionId) {
        try {
            redis.delete(sessionId);
            return true;
        } catch (Exception e) {
            log.error("清除历史失败: {}", sessionId, e);
            return false;
        }
    }

    /**
     * 获取指定用户的所有会话ID
     * @param userId 用户ID
     * @return 会话ID集合
     */
    public Set<String> getAllSession(String userId) {
        return  this.wkRedisService.findKeysByPattern(REDIS_KEY_PREFIX + userId + ":*");
    }

    /**
     * 清除指定用户的所有会话
     * @param userId  用户ID
     * @return 清除的会话数量
     */
    public long clearAllSession(String userId) {
       return this.wkRedisService.deleteKeysByPattern(REDIS_KEY_PREFIX + userId + ":*");
    }

    /**
     * 获取所有会话ID
     * @return 会话ID集合
     */
    public Set<String> getAllSession() {
        return  this.wkRedisService.findKeysByPattern(REDIS_KEY_PREFIX + "*");
    }
   /*
    * 清除所有会话
    * @return 清除的会话数量
    */
    public long clearAllSession() {
        return this.wkRedisService.deleteKeysByPattern(REDIS_KEY_PREFIX + "*");
    }
}
